﻿using System;
using System.Threading;

namespace Basic.RateLimit.Handler
{
    /// <summary>
    /// 请求频率限制器
    /// </summary>
    public class RateLimitHandler
    {
        private readonly object _locker = new object();

        private int Counts;

        public DateTime Time { get; private set; }
        public EnumRateLimitingUnit Unit { get; set; }
        public int MaxLimit { get; set; }

        public RateLimitHandler(int maxLimit, EnumRateLimitingUnit unit = EnumRateLimitingUnit.Minutes)
        {
            MaxLimit = maxLimit;
            Unit = unit;
            Time = GetTime(unit);
        }

        public bool CheckRateLimit()
        {
            var now = GetTime(Unit);
            if (now != Time)
            {
                lock (_locker)
                {
                    Time = now;
                    Counts = 0;
                }
            }
            if (Counts < MaxLimit)
            {
                Interlocked.Increment(ref Counts);
                return true;
            }
            return false;
        }

        private DateTime GetTime(EnumRateLimitingUnit unit)
        {
            DateTime now = DateTime.Now;
            Time = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
            switch (unit)
            {
                case EnumRateLimitingUnit.Seconds:
                    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, now.Second);
                case EnumRateLimitingUnit.Minutes:
                    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0);
                case EnumRateLimitingUnit.Hours:
                    return new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
                default:
                    return new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0);
            }
        }

    }

    /// <summary>
    /// 限流时间单位
    /// </summary>
    public enum EnumRateLimitingUnit : int
    {
        /// <summary>
        /// 秒
        /// </summary>
        Seconds = 0,
        /// <summary>
        /// 分钟
        /// </summary>
        Minutes = 1,
        /// <summary>
        /// 小时
        /// </summary>
        Hours = 2,
    }
}